import requests

from flask import jsonify, current_app, g
from sqlalchemy import asc
from apps.interface.business.interfacecasedata import InterfaceCaseDataBusiness
from apps.interface.business.interfaceproject import InterfaceProjectBusiness
from apps.interface.business.interfacesync import InterfaceSyncBusiness
from apps.interface.models.interfaceapimsg import InterfaceApiMsg
from apps.interface.models.interfacecasedata import InterfaceCaseData
from apps.interface.models.interfacecase import InterfaceCase
from apps.interface.models.interfacemodule import InterfaceModule
from apps.interface.models.interfaceproject import InterfaceProject
from apps.interface.models.interfacecaseset import InterfaceCaseSet
from apps.interface.util.global_variable import *
from apps.interface.util.global_variable import FILE_ADDRESS
from apps.interface.util.http_run import RunCase
from apps.interface.util.utils import *
from library.api.db import db
from apps.auth.extentions import parse_pwd
from apps.interface.settings.config import TOOL_BASE_URL


class InterfaceApiMsgBusiness(object):
    
    @classmethod
    def _query(cls):
        return InterfaceApiMsg.query.add_columns(
            InterfaceApiMsg.id.label('id'),
            InterfaceApiMsg.num.label('num'),
            InterfaceApiMsg.name.label('name'),
            InterfaceApiMsg.desc.label('desc'),
            InterfaceApiMsg.api_type.label('api_type'),
            InterfaceApiMsg.variable_type.label('variable_type'),
            InterfaceApiMsg.status_url.label('status_url'),
            InterfaceApiMsg.up_func.label('up_func'),
            InterfaceApiMsg.down_func.label('down_func'),
            InterfaceApiMsg.method.label('method'),
            InterfaceApiMsg.variable.label('variable'),
            InterfaceApiMsg.json_variable.label('json_variable'),
            InterfaceApiMsg.param.label('param'),
            InterfaceApiMsg.url.label('url'),
            InterfaceApiMsg.extract.label('extract'),
            InterfaceApiMsg.validate.label('validate'),
            InterfaceApiMsg.header.label('header'),
            InterfaceApiMsg.module_id.label('module_id'),
            InterfaceApiMsg.project_id.label('project_id'),
            InterfaceApiMsg.dubbo_interface.label('dubbo_interface'),
            InterfaceApiMsg.dubbo_method.label('dubbo_method'),
            InterfaceApiMsg.dubbo_version.label('dubbo_version'),
        )
    
    @classmethod
    def apimsg_create(cls, num, name, desc, variable_type, api_type, status_url, up_func, down_func,
                      method, variable,
                      json_variable, param, url, extract, validate, header, module_id, project_id,
                      dubbo_interface,
                      dubbo_method, dubbo_version, base_encryption):
        try:
            m = InterfaceApiMsg(
                num=num,
                name=name,
                desc=desc,
                variable_type=variable_type,
                api_type=api_type,
                status_url=status_url,
                up_func=up_func,
                down_func=down_func,
                method=method,
                variable=variable,
                json_variable=json_variable,
                param=param,
                url=url,
                extract=extract,
                validate=validate,
                header=header,
                module_id=module_id,
                project_id=project_id,
                dubbo_interface=dubbo_interface,
                dubbo_method=dubbo_method,
                dubbo_version=dubbo_version,
                user_id=g.userid,
                encryption=base_encryption
            )
            db.session.add(m)
            db.session.commit()
            return m.id, m.num
        except Exception as e:
            current_app.logger.error(str(e))
            return 102, str(e)
    
    @classmethod
    def apimsg_delete(cls, id):
        try:
            m = InterfaceApiMsg.query.get(id)
            m.status = InterfaceApiMsg.DISABLE
            db.session.add(m)
            db.session.commit()
            return 0
        except Exception as e:
            current_app.logger.error(str(e))
            return 105, str(e)
    
    @classmethod
    def apimsg_modify(cls, id, name, desc, variable_type, status_url, up_func, down_func, method,
                      variable, json_variable, param, url, extract, validate, header, module_id,
                      project_id, dubbo_interface, dubbo_method, dubbo_version, base_encryption,
                      is_sync, api_type):
        try:
            # 增加修改者id
            modified_user = g.userid
            m = InterfaceApiMsg.query.get(id)
            m.name = name,
            m.desc = desc,
            m.variable_type = variable_type,
            m.status_url = status_url,
            m.up_func = up_func,
            m.down_func = down_func,
            m.method = method,
            m.variable = variable,
            m.json_variable = json_variable,
            m.param = param,
            m.url = url,
            m.extract = extract,
            m.validate = validate,
            m.header = header,
            m.module_id = module_id,
            m.project_id = project_id,
            m.dubbo_interface = dubbo_interface,
            m.dubbo_method = dubbo_method,
            m.dubbo_version = dubbo_version,
            m.encryption = base_encryption,
            m.is_sync = is_sync
            m.modified_user = modified_user
            m.api_type = api_type
            db.session.add(m)
            db.session.commit()
            return 0, None
        except Exception as e:
            current_app.logger.error(str(e))
            return 102, str(e)
    
    @classmethod
    def add_api_msg(cls, project_name, api_msg_name, variable_type, api_type, desc_string, header,
                    extract, validate, api_msg_id, up_func, down_func, method, module_id, url,
                    status_url, variable, json_variable, param, all_project_id, number,
                    dubbo_interface, dubbo_method, dubbo_version):
        if not project_name:
            return jsonify({'msg': '项目不能为空', 'status': 0})
        if not module_id:
            return jsonify({'msg': '接口模块不能为空', 'status': 0})
        if not api_msg_name:
            return jsonify({'msg': '接口名称不能为空', 'status': 0})
        if method == -1:
            return jsonify({'msg': '请求方式不能为空', 'status': 0})
        if not url and api_type == 'http':
            return jsonify({'msg': '接口url不能为空', 'status': 0})
        if status_url == -1:
            if 'http' not in url:
                return jsonify({'msg': '基础url为空时，请补全api地址', 'status': 0})
        
        # 非http请求清除url
        if api_type != 'http':
            url = ''
        
        project_id = InterfaceProject.query.filter_by(name=project_name,
                                                      status=InterfaceProject.ACTIVE,
                                                      all_project_id=all_project_id).first().id
        num = auto_num(number, InterfaceApiMsg, module_id=module_id, status=InterfaceApiMsg.ACTIVE)
        # header单独处理
        e_header = cls.get_extract_header_variable(header)
        e_variable = cls.get_extract_header_variable(variable)
        e_param = cls.get_extract_header_variable(param)
        msg_encryption = {
            'header': e_header,  # 请求头
            'variable': e_variable,  # body
            'param': e_param
        }
        if json_variable:
            msg_encryption['json_variable'] = json_variable
        current_app.logger.info(msg_encryption)
        json.dumps(msg_encryption)
        base_encryption = parse_pwd(str(msg_encryption))
        
        if api_msg_id:
            # 获取之前的encryption
            is_sync = InterfaceSyncBusiness.contrast_encryption(api_msg_id, base_encryption)
            current_app.logger.info(is_sync)
            old_data = InterfaceApiMsg.query.filter_by(id=api_msg_id,
                                                       status=InterfaceApiMsg.ACTIVE).first()
            old_num = old_data.num
            if InterfaceApiMsg.query.filter_by(name=api_msg_name, module_id=module_id,
                                               status=0).first() and api_msg_name != old_data.name:
                return jsonify({'msg': '接口名字重复', 'status': 0})
            
            list_data = InterfaceApiMsg.query.filter_by(module_id=module_id, status=0).order_by(
                asc(InterfaceApiMsg.num)).all()
            
            num_sort(num, old_num, list_data, old_data)
            InterfaceApiMsgBusiness.apimsg_modify(api_msg_id, api_msg_name, desc_string,
                                                  variable_type, status_url, up_func,
                                                  down_func, method, variable, json_variable, param,
                                                  url, extract, validate, header, module_id,
                                                  project_id, dubbo_interface, dubbo_method,
                                                  dubbo_version, base_encryption, is_sync, api_type)
            return jsonify({'msg': '修改成功', 'status': 1, 'api_msg_id': api_msg_id, 'num': num})
        else:
            if InterfaceApiMsg.query.filter_by(name=api_msg_name, module_id=module_id,
                                               status=0).first():
                return jsonify({'msg': '接口名字重复', 'status': 0})
            else:
                interface_id, interface_num = InterfaceApiMsgBusiness.apimsg_create(num,
                                                                                    api_msg_name,
                                                                                    desc_string,
                                                                                    variable_type,
                                                                                    api_type,
                                                                                    status_url,
                                                                                    up_func,
                                                                                    down_func,
                                                                                    method,
                                                                                    variable,
                                                                                    json_variable,
                                                                                    param, url,
                                                                                    extract,
                                                                                    validate,
                                                                                    header,
                                                                                    module_id,
                                                                                    project_id,
                                                                                    dubbo_interface,
                                                                                    dubbo_method,
                                                                                    dubbo_version,
                                                                                    base_encryption)
                return jsonify(
                    {'msg': '新建成功', 'status': 1, 'api_msg_id': interface_id, 'num': interface_num})
    
    @classmethod
    def edit_api_msg(cls, case_id):
        
        _edit = InterfaceApiMsg.query.filter_by(id=case_id, status=InterfaceApiMsg.ACTIVE).first()
        _data = {
            'name': _edit.name, 'num': _edit.num, 'desc': _edit.desc, 'url': _edit.url,
            'method': _edit.method, 'status_url': int(_edit.status_url),
            'up_func': json.loads(_edit.up_func), 'down_func': json.loads(_edit.down_func),
            'variableType': _edit.variable_type,
            'param': json.loads(_edit.param),
            'header': json.loads(_edit.header),
            'variable': json.loads(_edit.variable),
            'json_variable': _edit.json_variable,
            'extract': json.loads(_edit.extract),
            'validate': json.loads(_edit.validate),
            'api_type': _edit.api_type,
            'dubbo_interface': _edit.dubbo_interface,
            'dubbo_method': _edit.dubbo_method,
            'dubbo_version': _edit.dubbo_version,
        }
        
        return jsonify({'data': _data, 'status': 1})
    
    @classmethod
    def run_api_msg(cls, api_msg_data, project_name, config_id):
        
        if not api_msg_data:
            return jsonify({'msg': '请勾选信息后，再进行测试', 'status': 0})
        
        # 前端传入的数据不是按照编号来的，重新排序
        api_ids = [(item['num'], item['apiMsgId']) for item in api_msg_data]
        api_ids.sort(key=lambda x: x[0])
        api_ids = [c[1] for c in api_ids]
        
        project_id = InterfaceProject.query.filter_by(name=project_name,
                                                      status=InterfaceProject.ACTIVE).first().id
        try:
            d = RunCase(project_id)
            res = json.loads(d.run_case(d.get_api_test(api_ids, config_id)))
        except Exception as e:
            current_app.logger.info("单个接口运行的错误信息:" + str(e))
            return jsonify({'msg': str(e), 'rs': '参数或者文件配置错误，请检查完再运行', 'status': 0})
        
        return jsonify({'msg': '测试完成', 'data': res, 'status': 1})
    
    @classmethod
    def find_api_msg(cls, project_name, module_id, api_name, page, per_page, api_type):
        if not project_name:
            return jsonify({'msg': '请选择项目', 'status': 0})
        if not module_id:
            return jsonify({'msg': '请先创建{}项目下的模块'.format(project_name), 'status': 0})
        # 处理用例中添加模块用例
        if api_type == 2:
            if api_name:
                case_data = InterfaceCase.query.filter_by(case_set_id=module_id,
                                                          status=InterfaceCaseSet.ACTIVE,
                                                          type=api_type).filter(
                    InterfaceCase.name.like('%{}%'.format(api_name))).all()
                total = len(case_data)
                if not case_data:
                    return jsonify({'msg': '没有该接口信息', 'status': 0})
            else:
                case_data = InterfaceCase.query.filter_by(case_set_id=module_id,
                                                          status=InterfaceCaseSet.ACTIVE,
                                                          type=api_type)
                pagination = case_data.order_by(InterfaceCase.num.asc()).paginate(page,
                                                                                  per_page=per_page,
                                                                                  error_out=False)
                case_data = pagination.items
                total = pagination.total
            
            _case = [{
                'case_id': c.id,
                'apiType': 'action',
                'num': c.num,
                'name': c.name,
                'desc': c.desc,
                'type': 'action',
                'time': 1,
                'status': True
                
            }
                for c in case_data]
            return jsonify({'data': _case, 'total': total, 'status': 1})
        
        if api_name:
            api_data = InterfaceApiMsg.query.filter_by(module_id=module_id, status=0).filter(
                InterfaceApiMsg.name.like('%{}%'.format(api_name))).all()
            total = len(api_data)
            if not api_data:
                return jsonify({'msg': '没有该接口信息', 'status': 0})
        else:
            api_data = InterfaceApiMsg.query.filter_by(module_id=module_id, status=0)
            pagination = api_data.order_by(InterfaceApiMsg.num.asc()).paginate(page,
                                                                               per_page=per_page,
                                                                               error_out=False)
            api_data = pagination.items
            total = pagination.total
        
        _api = [{
            'num': c.num,
            'name': c.name,
            'desc': c.desc,
            'url': c.url,
            'header': json.loads(c.header),
            'apiMsgId': c.id,
            'apiType': c.api_type,
            'gather_id': c.module_id,
            'variableType': c.variable_type,
            'variable': json.loads(c.variable),
            'json_variable': c.json_variable,
            'extract': json.loads(c.extract),
            'validate': json.loads(c.validate),
            'param': json.loads(c.param),
            'dubboInterface': c.dubbo_interface,
            'dubboMethod': c.dubbo_method,
            'dubboVersion': c.dubbo_version,
            'statusCase': {
                'extract': [True, True], 'variable': [True, True],
                'validate': [True, True], 'param': [True, True], 'header': [True, True]
            },
            'status': True, 'case_name': c.name, 'down_func': c.down_func, 'up_func': c.up_func,
            'time': 1,
            'is_sync': c.is_sync
        }
            for c in api_data]
        
        return jsonify({'data': _api, 'total': total, 'status': 1})
    
    @classmethod
    def del_api_msg(cls, api_msg_id):
        
        _data = InterfaceApiMsg.query.filter_by(id=api_msg_id, status=0).first()
        
        project_id = InterfaceModule.query.filter_by(id=_data.module_id,
                                                     status=0).first().project_id
        # if current_user.id != InterfaceProject.query.filter_by(id=project_id).first().user_id:
        #     return jsonify({'msg': '不能删除别人项目下的接口', 'status': 0})
        
        InterfaceApiMsgBusiness.apimsg_delete(api_msg_id)
        
        # 同步删除接口信息下对应用例下的接口步骤信息
        for d in InterfaceCaseData.query.filter_by(api_msg_id=api_msg_id, execute_status=0).all():
            InterfaceCaseDataBusiness.casedata_delete(d.id)
        
        return jsonify({'msg': '删除成功', 'status': 1})
    
    @classmethod
    def api_upload(cls, file, skip):
        
        if os.path.exists(os.path.join(FILE_ADDRESS, file.filename)) and not skip:
            return jsonify({"msg": "文件已存在，请修改文件名字后再上传", "status": 0})
        else:
            file.save(os.path.join(FILE_ADDRESS, file.filename))
            return jsonify(
                {'data': os.path.join(FILE_ADDRESS, file.filename), "msg": "上传成功", "status": 1})
    
    @classmethod
    def case_file_upload(cls, file):
        """上传文件到服务器上
        :param file:
        :return:
        """
        file.save(os.path.join(FILE_ADDRESS, file.filename))
        return {'data': os.path.join(FILE_ADDRESS, file.filename), "msg": "上传成功", "status": 1}
    
    @classmethod
    def import_api_msg(cls, all_project_id, project_name, module_id, import_type, import_url):
        if 'swagger' == import_type:
            parse_url = TOOL_BASE_URL + 'parse/swagger/tag/paths'
            data = {'content': '', 'parseAddress': import_url, 'type': import_type}
            request_session = requests.session()
            result = request_session.post(url=parse_url, json=data,
                                          headers={'Content-Type': 'application/json'})
            result_data = result.json()
            if result_data.get('code') == 0:
                return 0, result_data.get('data'), result_data.get('message')
            return 1, [], '解析出错了'
    
    @classmethod
    def save_import_api(cls, all_project_id, project_name, parse_data, import_type, import_url):
        if 'swagger' == import_type:
            req_body = [item.get('name') for item in parse_data]
            parse_url = TOOL_BASE_URL + 'parse/swagger/getApiByPath'
            data = {'id': 1010, 'tagPaths': req_body, 'url': import_url}
            request_session = requests.session()
            result = request_session.post(url=parse_url, json=data,
                                          headers={'Content-Type': 'application/json'})
            result_data = result.json()
            if result_data.get('code') == 0:
                api_module = {}
                status_url = 0
                env_tag = False
                interface_project_data = InterfaceProject.query.filter_by(name=project_name,
                                                                          status=InterfaceProject.ACTIVE,
                                                                          all_project_id=all_project_id).first()
                result_paths_data = result_data.get('data').get('parseContentVO')
                if not result_paths_data:
                    return 0, {}, '导入成功'
                for path_data in result_paths_data:
                    if not env_tag:
                        status_url = InterfaceProjectBusiness.modify_project_env(
                            interface_project_data,
                            "http://{}".format(
                                path_data.get('host')))
                        env_tag = True
                    
                    module_name = path_data.get('tag')
                    if api_module.get(module_name) is None:
                        module_data = InterfaceModule.query.filter_by(status=InterfaceModule.ACTIVE,
                                                                      project_id=interface_project_data.id,
                                                                      name=module_name).first()
                        if module_data:
                            api_module[module_name] = module_data.id
                        else:
                            num = auto_num(0, InterfaceModule, project_id=interface_project_data.id,
                                           status=InterfaceModule.ACTIVE)
                            m = InterfaceModule(
                                name=module_name,
                                project_id=interface_project_data.id,
                                num=num,
                            )
                            db.session.add(m)
                            db.session.commit()
                            api_module[module_name] = m.id
                    
                    module_id = api_module.get(module_name)
                    num = auto_num(0, InterfaceApiMsg, module_id=module_id,
                                   status=InterfaceApiMsg.ACTIVE)
                    request_params = path_data.get('request')
                    query_params = []
                    body_params = "{}"
                    if request_params.get('queryParams'):
                        for key in request_params.get('queryParams'):
                            query_params.append(
                                {"key": key, "value": request_params.get('queryParams')[key]})
                    
                    if request_params.get('bodyParams'):
                        body_params = request_params.get('bodyParams')
                    api_data = InterfaceApiMsg.query.filter_by(status=InterfaceApiMsg.ACTIVE,
                                                               method=path_data.get('method'),
                                                               project_id=interface_project_data.id,
                                                               url=path_data.get('url')).first()
                    variable_data = [
                        {"key": None, "param_type": "string", "remark": None, "value": None}]
                    if api_data:
                        pass
                    else:
                        cls.apimsg_create(num, path_data.get('pathName'), '', 'json', 'http',
                                          status_url, "[]", "[]",
                                          path_data.get('method'), json.dumps(variable_data),
                                          body_params, json.dumps(query_params),
                                          path_data.get('url'), "[]", "[]", "[]",
                                          module_id,
                                          interface_project_data.id, "", "", "", "")
                return 0, {}, '导入成功'
        return 1, {}, '导入失败'
    
    @classmethod
    def get_extract_header_variable(cls, public_values):
        """
        处理header、variable的方法
        :param public_values:
        :return: public_value_list
        """
        try:
            if isinstance(public_values, str):
                public_values = json.loads(public_values)
            if public_values is None:
                return None
            # todo 可以考虑用dict存储
            public_values_list = []
            for i in range(len(public_values)):
                public_value_dict = public_values[i]
                # key、value不为空，-> list
                if public_value_dict['key'] is not None and public_value_dict['key'] != '':
                    public_values_list.append(public_value_dict['key'])
                if public_value_dict['value'] is not None and public_value_dict['value'] != '':
                    public_values_list.append(public_value_dict['value'])
            # header为[] -> None
            if not public_values_list:
                return None
            return public_values_list
        # 异常默认为header为None
        except Exception as e:
            current_app.logger.info(str(e))
            return None
